import { GAssetImpl } from "../../../Core/GLoader/GLoader";
import { Res } from "../../Common/UIResources";
import GameMgr from "../../Logic/GameMgr";
import { INVALID_VALUE, IS_EMPTY_INVALID } from './../../../Core/CoreDefine';
import { NewFillArray, ObjectWrap } from './../../../Core/FrameEx/ES5Ex';
import { JXBtlArrIx } from './JXBattleDefine';
import { ANIMATION_SPEED } from "./JXRBCmdMgr";
import { COMMON_ANI_NAME, JXBattleBuffRoot, JXBattleBulletRoot, JXBattleEffectsRoot, JXBattleSkillSpine, JXCollisionRoot, JXSceneEffect } from './JXULDefine';

/**战斗资源加载类 */
export class BattleAssets extends ObjectWrap {

	public assetImpl: GAssetImpl = null;

	private _spritePool: cc.NodePool = null;

	constructor(key: string) {
		super();
		this.assetImpl = GAssetImpl.getAssetImpl(key);
		this._spritePool = new cc.NodePool()
	}

	/** 加载资源 */
	public preLoads(endCb: any, ...allAssets) {
		this.assetImpl.preLoads((curIndx: number, totalCount: number, path: string, err: Error, asset: typeof cc.Asset) => {
			if (curIndx == totalCount) {
				endCb();
			}
		},
			{ type: cc.Prefab, path: Res.prefab.fight.role },
			{ type: cc.Prefab, path: Res.prefab.fight.head },
			{ type: cc.Prefab, path: Res.prefab.fight.fightFlags },
			...allAssets);
	}


	/**
	  * 加载所有回合战斗资源
	  * @param iTeams 交战双方队伍信息
	  * @param sceneId 场景ID
	  * @param endCb 加载完成回调
	  */
	public loadAllRoundAssets(iTeams: IMonsterBtl[], sceneId: number, endCb: any) {
		let allPaths = [];
		let allAssets = [];
		this.loadSceneAssets(allAssets, allPaths)
		for (let i = 0; i < iTeams.length; i++) {
			this.loadTeamAssets(iTeams[i] as IMonsterBtl, allAssets, allPaths);
		}
		allAssets.push()
		this.preLoads((curIndx: number, totalCount: number, asset: cc.Asset) => endCb(),
			// { type: cc.SpriteAtlas, path: Res.texture.fight.describe }，
			...allAssets);
	}

	/**
	   * 加载场景特效资源
	   * @param assets -
	   * @param paths -
	  */
	public loadSceneAssets(assets: AssetInfo[], paths: string[]) {
		let keys = Object.keys(JXSceneEffect);
		for (let i = 0; i < keys.length; i++) {
			let path = JXSceneEffect[keys[i]];
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: sp.SkeletonData, path: path });
				paths.push(path);
			}
		}
	}


	/**
	  * 加载队伍资源
	  * @param iTeam 队伍信息
	  * @param assets -
	  * @param paths -
	*/
	public loadTeamAssets(iTeam: IMonsterBtl, assets: AssetInfo[], paths: string[]) {
		for (let i = 0; i < iTeam.partnerData.length; i++) {
			let card = iTeam.partnerData[i];
			let index = iTeam.heroIds.indexOf(card.heroId);
			if (index == INVALID_VALUE) continue;
			this.loadHeroAssets(card.tableId, card.skillIds, assets, paths);
		}
	}

	/**
	 * 加载英雄数据
	 * @param tableId 英雄静态表ID
	 * @param skills 英雄技能信息
	 * @param assets -
	 * @param paths -
	 */
	public loadHeroAssets(tableId: number, skills: number[], assets: AssetInfo[], paths: string[]) {
		let cardRaw = GameMgr.heroData.getRaw<SHeroDataRaw>(tableId)
		let path = Res.model + cardRaw.animation + '/' + cardRaw.animation;
		if (!this.hasLoadAsset(paths, path)) {
			assets.push({ type: sp.SkeletonData, path });
			paths.push(path);
		}
		let aPath1 = Res.audio.battle + cardRaw.atkAudio;
		if (!this.hasLoadAsset(paths, aPath1)) {
			assets.push({ type: cc.AudioClip, path: aPath1 });
			paths.push(aPath1);
		}
		for (let i = 0; i < skills.length; i++) {
			let skillId = skills[i];
			if (IS_EMPTY_INVALID(skillId)) continue;
			this.loadSkillAsset(skillId, assets, paths);
		}
		this.loadActionAsset(cardRaw.action, assets, paths);
	}


	/**
	 * 加载技能资源
	 * @param skillId 技能ID
	 * @param assets -
	 * @param paths -
	 */
	public loadSkillAsset(skillId: number, assets: AssetInfo[], paths: string[]) {
		let skillRaw = GameMgr.skillData.getRaw<SSkillDataRaw>(skillId);
		if (!skillRaw) return;
		// if (skillRaw.type == JXBtlST.Passive) return;
		if (skillRaw.skillSk) {
			let path = JXBattleSkillSpine + skillRaw.skillSk;
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: sp.SkeletonData, path });
				paths.push(path);
			}
		}
		let aPath1 = Res.audio.battle + skillId;
		if (!this.hasLoadAsset(paths, aPath1)) {
			assets.push({ type: cc.AudioClip, path: aPath1 });
			paths.push(aPath1);
		}
		this.loadActionAsset(skillRaw.animGroup[JXBtlArrIx.One], assets, paths);
		if (skillRaw.eAnimId.length > 0) {
			for (let i = 0; i < skillRaw.eAnimId.length; i++) {
				if (skillRaw.eAnimId[i]) {
					this.loadEffectAnim(skillRaw.eAnimId[i], assets, paths);
				}
			}
		}
	}

	/**
	    * 加载战斗表现动作配置资源
	    * @param actionId 动作表ID
	    * @param assets -
	    * @param paths -
	   */
	public loadActionAsset(actionId: number, assets: AssetInfo[], paths: string[]) {
		let actionRaw = GameMgr.action.getRaw<SActionRaw>(actionId);
		if (!actionRaw) return;
		if (actionRaw.collision && actionRaw.collision.length > 0) {
			for (let i = 0, l = actionRaw.collision.length; i < l; i++) {
				this.loadCollision(actionRaw.collision[i], assets, paths);
			}
		}
		let bullet = actionRaw.bullet;
		if (bullet && bullet.length > 0) {
			for (let i = 0; i < bullet.length; i++) {
				this.loadBulletAsset(bullet[i], assets, paths);
			}
		}
		let effect = actionRaw.effect;
		if (effect) {
			let path = JXBattleEffectsRoot + effect[JXBtlArrIx.Zero];
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: cc.SpriteAtlas, path });
				paths.push(path);
			}
		}
	}


	/**
	 * 加载子弹资源
	 * @param bulletId 子弹表ID
	 * @param assets -
	 * @param paths -
	 */
	public loadBulletAsset(bulletId: number, assets: AssetInfo[], paths: string[]) {
		let bulletRaw = GameMgr.bullet.getRaw<SBulletRaw>(bulletId);
		if (!bulletRaw) return;
		if (bulletRaw.isSpine) {
			let path = JXBattleSkillSpine + bulletRaw.aniconfig[JXBtlArrIx.Zero];
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: sp.SkeletonData, path });
				paths.push(path);
			}
		}
		else {
			let path = JXBattleBulletRoot + bulletRaw.aniconfig[JXBtlArrIx.Zero];
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: cc.SpriteAtlas, path });
				paths.push(path);
			}
		}
	}


	/**
	* 加载buff特效资源
	* @param eaniId BUFF配置
	* @param assets -
	* @param paths -
	*/
	public loadEffectAnim(eaniId: number, assets: AssetInfo[], paths: string[]) {
		let effectAniRaw = GameMgr.effectAnim.getRaw<SEffectAnimRaw>(eaniId);
		if (!effectAniRaw) return;
		for (let i = 0; i < effectAniRaw.effect.length; i++) {
			let path = JXBattleBuffRoot + effectAniRaw.effect[i][JXBtlArrIx.Zero];
			if (!this.hasLoadAsset(paths, path)) {
				assets.push({ type: cc.SpriteAtlas, path });
				paths.push(path);
			}
		}
		if (effectAniRaw.collision) {
			this.loadCollision(effectAniRaw.collision, assets, paths);
		}

	}

	/**
	 * 加载碰撞信息
	 * @param collisionId 碰撞ID
	 * @param assets -
	 * @param paths -
	  */
	public loadCollision(collisionId: number, assets: AssetInfo[], paths: string[]) {
		let collision = GameMgr.actionCollision.getRaw<SActionCollisionRaw>(collisionId);
		if (!collision) return;
		for (let i = 0; i < collision.effect.length; i++) {
			if (collision.isSpine) {
				let path = JXBattleSkillSpine + collision.effect[i][JXBtlArrIx.Zero];
				if (!this.hasLoadAsset(paths, path)) {
					assets.push({ type: sp.SkeletonData, path });
					paths.push(path);
				}
			} else {
				let path = JXCollisionRoot + collision.effect[i][JXBtlArrIx.Zero];
				if (!this.hasLoadAsset(paths, path)) {
					assets.push({ type: cc.SpriteAtlas, path });
					paths.push(path);
				}
			}
		}
	}



	/**
	    * 检测paths中是否包含path
	    * @param paths -
	    * @param path -
	  */
	public hasLoadAsset(paths: string[], path: string): boolean {
		return paths.indexOf(path) != INVALID_VALUE;
	}

	/**
	  * 创建一个帧动画
	  * @param config 帧动画配置
	  * @param wrapModel 循环模式
	  * @param rootPath 资源根目录
	  */
	public createEffectsAnimation(config: FrameAniConfigure, wrapModel, rootPath: string): cc.AnimationClip {
		let assetPath = rootPath + config[JXBtlArrIx.Zero];
		let asset = this.assetImpl.getPreLoadAsset<cc.SpriteAtlas>(assetPath);
		if (!asset) {
			cc.log("找不到资源：" + assetPath);
			return;
		}
		GAssetImpl.checkAtlasDyPack(assetPath, asset);
		let clips = this.assetImpl.atlasJXLoadClips(asset, {    /** clip name */
			aniName: COMMON_ANI_NAME,
			/** 前缀 */
			prefix: config[JXBtlArrIx.One],
			/** 数值位数 */
			numberFix: config[JXBtlArrIx.Two],
			/** 起始数值索引 */
			minIdx: 1,
			/** 结束数值索引 */
			maxIdx: config[JXBtlArrIx.Three]
		});
		let clip = clips[JXBtlArrIx.Zero];
		if (!clip) {
			cc.log(`帧动画配置BUG 资源为${assetPath}, 配置为${JSON.stringify(config)}`);
		}
		clip.wrapMode = wrapModel;
		clip.sample = 30;
		clip.speed = ANIMATION_SPEED;
		return clip;
	}

	/**
	 * 创建一个帧动画
	 * @param aniConfig 动画配置
	 * @param root 根目录
	 * @param wrapModel 循环模式
	 * @param cb 回调
	 */
	public createEffect(aniConfig: FrameAniConfigure, root: string, wrapModel: cc.WrapMode, cb?): cc.Animation {
		let node = new cc.Node();
		let sp = node.addComponent(cc.Sprite);
		sp.type = cc.Sprite.Type.SIMPLE;
		sp.sizeMode = cc.Sprite.SizeMode.RAW;
		node.scale = aniConfig[JXBtlArrIx.Five];
		node.anchorY = 0;
		node.opacity = aniConfig[JXBtlArrIx.Six] * 255;
		if (aniConfig[JXBtlArrIx.Four]) {
			sp.setBlend(cc.macro.BlendFactor.SRC_ALPHA, cc.macro.BlendFactor.ONE);
		}
		sp.trim = false;
		let animation = node.addComponent(cc.Animation);
		let clip = this.createEffectsAnimation(aniConfig, wrapModel, root);
		animation.addClip(clip);
		animation.once(cc.Animation.EventType.FINISHED, () => {
			node.destroy();
			if (cb) cb();
		})
		return animation;
	}

	/**
	  * 创建一个spine
	  * @param path 
	  */
	public createSpine(path: string): sp.Skeleton {
		let spineNode = new cc.Node();
		let spine = spineNode.addComponent(sp.Skeleton);
		spine.premultipliedAlpha = false;
		spine.skeletonData = this.assetImpl.getPreLoadAsset<sp.SkeletonData>(path);
		return spine;
	}

	protected getNodeFormPoll(): cc.Node {
		if (this._spritePool.size()) {
			return this._spritePool.get()
		} else {
			let node = new cc.Node();
			let spr = node.addComponent(cc.Sprite)
			return spr.node;
		}
	}

	/**
	  * 创建一个文本
	  * @param desc 文本信息
	  */
	createDescribe(desc: string): cc.Node {
		let node = new cc.Node();
		let comp = node.addComponent(cc.Layout);
		comp.type = cc.Layout.Type.HORIZONTAL;
		let strArr = desc.split("|")
		let nodeLine: cc.Node[] = NewFillArray(strArr.length)
		for (let i = 0; i < strArr.length; i++) {
			let v = strArr[i];
			let img = this.getNodeFormPoll();
			this.assetImpl.spriteAtlasFrame(img.getComponent(cc.Sprite), Res.texture.fight.describe, v)
			nodeLine[i] = img;
			img.name = v;
		}

		nodeLine.forEach(item => {
			item.position = cc.Vec2.ZERO;
			item.parent = node;
		})

		comp.updateLayout();
		return comp.node;
	}

	recyclingDescribe(descNode: cc.Node) {
		descNode.children.forEach(node => {
			node.removeFromParent();
			node.name = "";
			node.scale = 1;
			node.opacity = 255;
			node.active = true;
			node.getComponent(cc.Sprite).spriteFrame = null;
			this._spritePool.put(node)
		})
	}

	public destroy() {
		this.assetImpl.release();
		this.assetImpl = null;
		this._spritePool.clear();
	}


}